package com.yum.ms.aop;

import cn.hutool.crypto.digest.MD5;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * @author Yum
 * @version 1.0
 */
@Component  //1.我是一个javaBean
@Aspect     //2.我是一个切面
public class RedisCacheAop {
    @Autowired
    private RedisTemplate redisTemplate;

    // 拦截一个为RedisCache的注解
    @Pointcut("@annotation(com.yum.ms.aop.RedisCache)") // 切点
    public void pc(){}


    @Around("pc()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        //取得方法签名
        MethodSignature signature = (MethodSignature) point.getSignature();
        //取得方法对象
        Method method = signature.getMethod();
        //取得缓存注解对象
        RedisCache redisCache = method.getAnnotation(RedisCache.class);
        //取得注解上的缓存时长
        int cacheTime = redisCache.seconds();
        //redis的key为类名:方法名:参数
        String className = point.getTarget().getClass().getName();
        String methodName = signature.getName();
        String argsJson = JSON.toJSONString(point.getArgs());
        String key = className;
        String hKey =  MD5.create().digestHex16(methodName+argsJson);


        //从缓存取得数据
        Object cacheData = redisTemplate.opsForHash().get(key,hKey);
        //命中缓存
        if (cacheData != null) {
            //返回缓存数据
            return cacheData;
        }
        //没命中缓存 执行方法
        Object result = point.proceed();
        //设置缓存，缓存时长为负数则永久缓存
        if (cacheTime < 0) {
            redisTemplate.opsForHash().put(key, hKey, result);
        } else {
            //缓存指定时长
            //redisTemplate.opsForValue().set(key, JSON.toJSONString(result), cacheTime, TimeUnit.SECONDS);
            redisTemplate.expire(key,cacheTime, TimeUnit.SECONDS);
        }
        return result;
    }
}
